package org.xtext.example.mydsl.validation;
 


import java.util.HashSet;
import java.util.Set;

import org.eclipse.xtext.validation.Check;
import org.xtext.example.mydsl.myDsl.Abs;
import org.xtext.example.mydsl.myDsl.App;
import org.xtext.example.mydsl.myDsl.Dich;
import org.xtext.example.mydsl.myDsl.Let;
import org.xtext.example.mydsl.myDsl.MyDslPackage;
import org.xtext.example.mydsl.myDsl.Nrif;
import org.xtext.example.mydsl.myDsl.Prog;
import org.xtext.example.mydsl.myDsl.Prog1;
import org.xtext.example.mydsl.myDsl.Tapp;
import org.xtext.example.mydsl.myDsl.Term;
import org.xtext.example.mydsl.myDsl.Uq;
import org.xtext.example.mydsl.myDsl.Var;
 

public class MyDslJavaValidator extends AbstractMyDslJavaValidator {

	@Check
	public void checkDuplicateBoundVariable(Abs term) {
		//new CheckDuplicateBoundVariable(this).doSwitch(term);
	}

	@Check
	public void checkDuplcateTypeVariable(Uq uq) {
		//new CheckDuplicateTypeVariable(this).doSwitch(uq);
	}	
	
	
	/**
	 * controlla se un termine è chiuso se il termine contiene variabli libere
	 * segnala un errore
	 * @param t termine
	 * @param variables
	 */
	
	@Check
	public void checkFreeVariable(Prog prog) {
		for (Dich d : prog.getD()) {
			checkFreeAux(d.getTerm(), new HashSet<String>());
		}
		checkFreeAux(prog.getMain(), new HashSet<String>());
	}
	
	@Check
	public void checkFreeVariable(Prog1 prog) {
		for (Dich d : prog.getD()) {
			checkFreeAux(d.getTerm(), new HashSet<String>());
		}
	}
	
	private void checkFreeAux(Term t, Set<String> variables) {

		if (t instanceof Var) {
			if (variables.add(((Var) t).getName())) {
				this.acceptError("Free variable", t,
						MyDslPackage.Literals.VAR__NAME, 0, "");
			}
		} else if (t instanceof Abs) {
			variables.add(((Abs) t).getParam());
			checkFreeAux(((Abs) t).getBody(), variables);
		} else if (t instanceof App) {
			checkFreeAux(((App) t).getT1(), clone(variables));
			checkFreeAux(((App) t).getT2(), variables);
		} else if (t instanceof Uq) {
			checkFreeAux(((Uq) t).getTerm(), variables);
		} else if (t instanceof Tapp) {
			checkFreeAux(((Tapp) t).getTerm(), variables);
		} else if (t instanceof Nrif) {
			checkFreeAux(((Nrif) t).getNome().getTerm(), variables);
		} else if (t instanceof Let) {
			checkFreeAux(((Let) t).getT1(), clone(variables));
			variables.add(((Let) t).getVar());
			checkFreeAux(((Let) t).getT2(), variables);
		}

	}

	public Set<String> clone(Set<String> set) {
		Set<String> clone = new HashSet<String>();
		for (String e : set)
			clone.add(e);
		return clone;
	}


	
}
